#include "test.hpp"
#include <iostream>
#include <stdexcept>
#include <array>
#include <vector>
#include <cassert>
#include <chrono>
#include <random>
#include <limits>
#include <numeric>
#include <algorithm>
#include <cmath>

#include "njm_device.hpp"
#include "njm_window.hpp"
#include "njm_model.hpp"
#include "njm_game_obj.hpp"
#include "keyboard_movement_controller.hpp"
#include "njm_buffer.hpp"
#include "njm_camera.hpp"
// #include "njm_renderer_noswapchain.hpp"
#include "njm_renderer.hpp"
// #include "systems/simple_render_system.hpp"
// #include "systems/point_light_system.hpp"
#include "njm_frame_info.hpp"

#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/gtc/constants.hpp>

static constexpr int WIDTH = 800;
static constexpr int HEIGHT = 800;
static constexpr float MAX_FRAME_TIME = 0.05f; // 50ms
static constexpr const char *MODEL_PATH = "src/models/md1.obj";

void test()
{std::cout << "test::test()" << std::endl;}

// void test()
// {
//     std::cout << "test::test()" << std::endl;
//     using namespace njm;
//     struct GlobalUbo
//     {
//         glm::mat4 projectionView{1.f};
//         glm::vec3 lightDirection = glm::normalize(glm::vec3{1.f, -1.f, 1.f});
//     };

//     NjmWindow njmWindow{WIDTH, HEIGHT, "FIRST APP"};
//     NjmDevice njmDevice{njmWindow};
//     NjmRenderer njmRenderer{njmWindow, njmDevice};

//     std::shared_ptr<NjmModel> objModel = NjmModel::createModelFromFile(njmDevice, MODEL_PATH);
//     auto gameObj = NjmGameObj::createGameObj();
//     gameObj.model = objModel;
//     gameObj.color = {0.1f, 0.8f, 0.1f};
//     gameObj.transform.translation = {.0f, .0f, 2.5f};
//     gameObj.transform.scale = {.5f, .5f, .5f};
//     std::vector<NjmGameObj> gameObjs;
//     gameObjs.push_back(std::move(gameObj));

//     std::unique_ptr<NjmBuffer> uboBuffer = std::make_unique<NjmBuffer>(
//         njmDevice,
//         sizeof(GlobalUbo),
//         1,
//         VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
//         VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
//     );
//     uboBuffer->map();

//     SimpleRenderSystem renderSys{njmDevice, njmRenderer.getSwapChainRenderPass()};
//     KeyboardMovementController cameraController{};
//     NjmGameObj viewerObject = NjmGameObj::createGameObj();
//     NjmCamera camera{};

//     auto currentTime = std::chrono::high_resolution_clock::now();
//     while (!njmWindow.shouldClose())
//     {
//         glfwPollEvents();
//         auto newTime = std::chrono::high_resolution_clock::now();
//         float frameTime = std::chrono::duration<float, std::chrono::seconds::period>(newTime - currentTime).count();
//         currentTime = newTime;
//         frameTime = glm::min(frameTime, MAX_FRAME_TIME);

//         cameraController.moveInPlaneXZ(njmWindow.getGLFWwindow(), frameTime, viewerObject);
//         camera.setViewYXZ(viewerObject.transform.translation, viewerObject.transform.rotation);
//         float aspect = njmRenderer.getAspectRatio();
//         camera.setPerspectiveProjection(glm::radians(50.f), aspect, 0.1f, 10.f);

//         if (auto cmdBuf = njmRenderer.beginFrame())
//         {
//             int frameIndex = njmRenderer.getFrameIndex();
//             FrameInfo frameInfo{frameIndex, frameTime, cmdBuf, camera};

//             // update
//             GlobalUbo ubo{};
//             ubo.projectionView = camera.getProjection() * camera.getView();
//             uboBuffer->writeToBuffer(&ubo);
//             uboBuffer->flush();
//             // bind
//             // render
//             njmRenderer.beginSwapChainRenderPass(cmdBuf);
//             renderSys.renderGameObjs(frameInfo, gameObjs);
//             njmRenderer.endSwapChainRenderPass(cmdBuf);
//             njmRenderer.endFrame();
//         }
//     }
//     vkDeviceWaitIdle(njmDevice.device());
// }